#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <functional>
#include "Log.hpp"
#include "MyMutex.hpp"
#include "mythread.hpp"

using namespace std;

static const int defaultnum = 5;

class ThreadData
{
public:
    ThreadData(const std::string &name) : threadname(name)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string threadname;
};

template <class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = defaultnum) : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        // 创建线程
        for (int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread-";
            threadname += to_string(i + 1);
            ThreadData td(threadname);

            // emplace_back方法的作用是构造并插入，减少拷贝次数
            lg.LogMessage(Info, "%s is created...\n", threadname.c_str());
            _threads.emplace_back(threadname, bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);
        }
    }
public:
    //最简单的懒汉模式，第一次调用才创建ThreadPool<T>对象，在C++11之后，该方法没有线程安全问题
    static ThreadPool<T>* GetInstance()
    {
        static ThreadPool<T> tp;
        return &tp;
    }

    bool Start()
    {
        for (auto &thread : _threads)
        {
            lg.LogMessage(Info, "%s is running ...\n", thread.getThreadName().c_str());
            thread.Start();
        }
        return true;
    }
    void ThreadWait(ThreadData &td)
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond,&_mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            // 取任务
            T t;
            {
                LockGuard lockguard(&_mutex);
                while (_q.empty()) // 提高代码的健壮性
                {
                    ThreadWait(td);
                    lg.LogMessage(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                }
                t = _q.front();
                _q.pop();
            }
            //处理任务
            t();
        }
    }
    void Push(T in)
    {
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeup();
    }

    // for debug
    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.join();
        }
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    queue<T> _q; // 任务队列
    vector<Thread<ThreadData>> _threads;

    int _thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};